//
// Created by LiuYou on 2021/8/7.
//

#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <cerrno>
#include <sys/syslog.h>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include "ThreadChannel.hpp"
#include "../include/NetRadioType.hpp"
#include "../include/Protocol.hpp"
#include "Server.hpp"
#include "MediaLib.hpp"


namespace NetRadio {
    namespace Server {
        namespace ThreadChannel {
            struct ThreadChannelEntry {
                ChannelId channelId;
                pthread_t tid;
            };
        }
    }
}


struct NetRadio::Server::ThreadChannel::ThreadChannelEntry
        threadChannelEntry[NetRadio::CHANNEL_NUM];
static int tidNextPos = 0;


static void*
threadChannelSender(void* ptr) {
    using NetRadio::Protocol::MsgChannel;
    struct MsgChannel* msgChannelBuf;
    void* pVoid = malloc( NetRadio::MSG_CHANNEL_MAX );
    msgChannelBuf = static_cast<struct MsgChannel*>(pVoid);
    if (msgChannelBuf == nullptr) {
        syslog( LOG_ERR, "malloc(): %s", strerror(errno));
        exit( 1 );
    }
//    int dataSize = NetRadio::MAX_DATA;

    struct NetRadio::Server::MediaLib::MediaLibEntry* mediaLibEntry = static_cast<NetRadio::Server::MediaLib::MediaLibEntry*>(ptr);
    msgChannelBuf->channelId = mediaLibEntry->channelId;
    while (true) {
        int len = NetRadio::Server::MediaLib::readChannelList( mediaLibEntry->channelId,
                                                               msgChannelBuf->data,
                                                               NetRadio::MAX_DATA );
        // TODO 注意: !!! 注意正确的头文件以及所需的头文件的导入。如果导入错误, 会出现非常多问题甚至是段错误。
        if (sendto( socketFd, msgChannelBuf, len + sizeof( NetRadio::ChannelId ), 0,
                    (sockaddr*) &senderAddress, sizeof( senderAddress )) < 0) {
            syslog( LOG_ERR, "threadChannelSender(%s):sendto(): %s", (char*)(mediaLibEntry->channelId), strerror(errno));
            exit( 1 );
        } else {
            syslog( LOG_DEBUG, "threadChannelSender(%s):sendto(): succeed.", (char*)(mediaLibEntry->channelId) );
        }

        sched_yield();
    }

    pthread_exit( nullptr );

}

int NetRadio::Server::ThreadChannel::
threadChannelCreate(NetRadio::Server::MediaLib::MediaLibEntry* ptrMediaLibEntry) {
    int err = pthread_create( &threadChannelEntry[tidNextPos].tid, nullptr,
                              threadChannelSender, ptrMediaLibEntry );
    if (err) {
        syslog( LOG_WARNING, "pthread_create(): %s", strerror( err ));
        return -err;
    }
    threadChannelEntry[tidNextPos].channelId = ptrMediaLibEntry->channelId;
    ++tidNextPos;

    return 0;
}

int NetRadio::Server::ThreadChannel::
threadChannelDestroy(NetRadio::Server::MediaLib::MediaLibEntry* ptrMediaLibEntry) {
    for (int i = 0; i < NetRadio::CHANNEL_NUM; ++i) {
        if (threadChannelEntry[i].channelId == ptrMediaLibEntry->channelId) {
            if (pthread_cancel( threadChannelEntry[i].tid ) < 0) {
                syslog( LOG_ERR, "pthread_cancel(): the thread of channel %d", ptrMediaLibEntry->channelId );
                return -ESRCH;
            }
        }

        pthread_join( threadChannelEntry[i].tid, nullptr );
        threadChannelEntry[i].channelId = -1;
        return 0;
    }

}

int NetRadio::Server::ThreadChannel::
threadChannelDestroyAll() {
    for (int i = 0; i < NetRadio::CHANNEL_NUM; ++i) {
        if (threadChannelEntry[i].channelId > 0) {
            if (pthread_cancel( threadChannelEntry[i].tid ) < 0) {
                syslog( LOG_ERR, "pthread_cancel(): the thread of channel %d", threadChannelEntry[i].channelId );
                return -ESRCH;
            }
            pthread_join( threadChannelEntry[i].tid, nullptr );
            threadChannelEntry[i].tid = -1;
        }
    }
    return 0;
}
